/*
 * enc_save.c
 *
 *  Created on: 2018年11月2日
 *  Author: Degang.Wu (windragon@126.com)
 *  Desc:
 */

#include "public.h"
#include "enc_save.h"
#include "enc_json_util.h"

#define JSON_ETHIO(ethio, ethioset)  	\
		ethio.AddMember(KEY_ENABLE, ethioset.ethio_isenable, allocator);	\
		ethio.AddMember(KEY_ETHID, ethioset.ethio_ethid, allocator);	\
		ethio.AddMember(KEY_SIPADDR, ethioset.ethio_sipaddr, allocator);	\
		ethio.AddMember(KEY_DIPADDR, ethioset.ethio_dipaddr, allocator);	\
		ethio.AddMember(KEY_SIPPORT, ethioset.ethio_sipport, allocator);	\
		ethio.AddMember(KEY_DIPPORT, ethioset.ethio_dipport, allocator);

#define UNJSON_ETHIO(ethioset, ethio)	\
		GET_INT_VALUE(ethioset.ethio_isenable, KEY_ENABLE, ethio, 0)	\
		GET_INT_VALUE(ethioset.ethio_ethid, KEY_ETHID, ethio, 0)	\
		GET_INT_VALUE(ethioset.ethio_sipaddr, KEY_SIPADDR, ethio, 0)	\
		GET_INT_VALUE(ethioset.ethio_dipaddr, KEY_DIPADDR, ethio, 0)	\
		GET_INT_VALUE(ethioset.ethio_sipport, KEY_SIPPORT, ethio, 0)	\
		GET_INT_VALUE(ethioset.ethio_dipport, KEY_DIPPORT, ethio, 0)

#define	 UNJSON_OUTPUT(outset, out) \
		GET_INT_VALUE(outset.out_proto, KEY_OUT_PROTO, out, 0)	\
		GET_INT_VALUE(outset.out_filte_nullpkt, KEY_OUT_FILTER_NULL_PKT, out, 0)	\
		GET_INT_VALUE(outset.out_enable_ip, KEY_OUT_ENABLE_IP, out, 0)	\
		GET_INT_VALUE(outset.out_enable_asi, KEY_OUT_ENABLE_ASI, out, 0)	\
		if (out.HasMember(KEY_ETHIO) && out[KEY_ETHIO].IsObject())	\
		{	\
			rapidjson::Value& ethio = out[KEY_ETHIO];	\
			stENC_ETHIOSET& ethioset = outset.out_ethio;	\
			UNJSON_ETHIO(ethioset, ethio)	\
		}

void shrmem_enc_load_mst(pENC_DEVSET_MASTER pMaster)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/%s", g_cfgpath, ENC_MST_CFG);
	std::string str;

	BW_INFO("master load...\n");

	if (NULL == pMaster)
	{
		return;
	}
	if (!u::io::File::exists(cfgfile))
	{
		return;
	}
	u::AutoHeap content;
	u::io::File::read(content, cfgfile);

	rapidjson::Document	doc;
	doc.Parse(content.head());
	if (doc.HasParseError())
	{
		return;
	}

	GET_INT_VALUE(pMaster->enc_appvsion, KEY_APPVER, doc, END_APP_SLV_VER);
	GET_INT_VALUE(pMaster->enc_setvsion, KEY_SET_VER, doc, 1);
	GET_INT_VALUE(pMaster->enc_savevsion, KEY_SAVE_VER, doc, 1);
	GET_INT_VALUE(pMaster->enc_curvsion, KEY_CURVER, doc, 0);

	GET_INT_VALUE(pMaster->enc_ethdevnum, KEY_ETH_NUM, doc, ENC_ETHIFMAX_MASTER);

	if (doc.HasMember(KEY_ETH_DEV) && doc[KEY_ETH_DEV].IsArray())
	{
		rapidjson::Value& ethdev = doc[KEY_ETH_DEV];
		for (uint i = 0; i < ethdev.Size() && i < ENC_ETHIFMAX_MASTER; i++)
		{
			GET_STR_VALUE(str, KEY_ETH_NAME, ethdev[i], "");
			if (str.empty())
			{
				memset(pMaster->enc_ethdevname[i], 0, sizeof(pMaster->enc_ethdevname[i]));
			}
			else
			{
				snprintf((char*)pMaster->enc_ethdevname[i], sizeof(pMaster->enc_ethdevname[i]), "%s", str.c_str());
			}
			GET_INT_VALUE(pMaster->enc_ethdevipaddr[i][0], KEY_ETH_IPADDR, ethdev[i], 0);
		}
	}

	// ip input
	if (doc.HasMember(KEY_IP_INPUT) && doc[KEY_IP_INPUT].IsArray())
	{
		rapidjson::Value& ipinput_arrays = doc[KEY_IP_INPUT];
		for (uint i = 0; i < ipinput_arrays.Size() && i < ENC_MAX_IPINPUT_NUM; i++)
		{
			rapidjson::Value& ipin = ipinput_arrays[i];
			stENC_IPINSET& ipinset = pMaster->enc_ipin[i];
			GET_INT_VALUE(ipinset.inp_enable, KEY_IPIN_ENABLE, ipin, 0);
			GET_INT_VALUE(ipinset.inp_igmp, KEY_IPIN_IGMP, ipin, 0);
			GET_INT_VALUE(ipinset.inp_proto, KEY_IPIN_PROTO, ipin, 0);
			if (ipin.HasMember(KEY_ETHIO) && ipin[KEY_ETHIO].IsObject())
			{
				rapidjson::Value& ethio = ipin[KEY_ETHIO];
				stENC_ETHIOSET& inp_ethio = ipinset.inp_ethio;

				UNJSON_ETHIO(inp_ethio, ethio);
			}
		}
	}

	// enc channel output
	if (doc.HasMember(KEY_ENC_OUTPUT) && doc[KEY_ENC_OUTPUT].IsArray())
	{
		rapidjson::Value& enc_out = doc[KEY_ENC_OUTPUT];
		for (uint i = 0; i < enc_out.Size() && i < ENC_TOTAL_CHLMAX; i++)
		{
			stENC_OUTSET& outset = pMaster->enc_output[i];
			rapidjson::Value& out = enc_out[i];
			UNJSON_OUTPUT(outset, out)
		}
	}

	// mux set
	if (doc.HasMember(KEY_MUX_SET) && doc[KEY_MUX_SET].IsObject())
	{
		stENC_MUXSET& muxset = pMaster->enc_mptsmux;
		rapidjson::Value& mux = doc[KEY_MUX_SET];
		GET_INT_VALUE(muxset.mux_maxrate_kb, KEY_MUX_RATE, mux, 0)
		GET_INT_VALUE(muxset.mux_origin_nid, KEY_MUX_ORG_NETID, mux, 0)
		GET_INT_VALUE(muxset.mux_netid, KEY_MUX_NETID, mux, 0)
		GET_INT_VALUE(muxset.mux_transid, KEY_MUX_TRANSID, mux, 0)
		GET_INT_VALUE(muxset.mux_pcr_correct, KEY_MUX_PCR_CORRECT, mux, 0)
	}

	// mux output
	if (doc.HasMember(KEY_MUX_OUTPUT) && doc[KEY_MUX_OUTPUT].IsObject())
	{
		stENC_OUTSET& outset = pMaster->enc_mptsout;
		rapidjson::Value& out = doc[KEY_MUX_OUTPUT];
		UNJSON_OUTPUT(outset, out)
	}


	for (uint i = 0; i < ENC_TOTAL_CHLMAX; i++)
	{
		shrmem_encchl_load(&pMaster->enc_chls[i], i);
	}
}

void shrmem_enc_save_mst(pENC_DEVSET_MASTER pMaster)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/%s", g_cfgpath, ENC_MST_CFG);
	if (NULL == pMaster)
	{
		return;
	}

	rapidjson::Document	doc;
	doc.SetObject();
	rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();

	rapidjson::Value strV(rapidjson::kStringType);
	rapidjson::Value numV(rapidjson::kNumberType);

	numV.SetInt(pMaster->enc_inited);
	doc.AddMember(KEY_INITED, numV, allocator);
	numV.SetInt(pMaster->enc_appvsion);
	doc.AddMember(KEY_APPVER, numV, allocator);
	numV.SetInt(pMaster->enc_setvsion);
	doc.AddMember(KEY_SET_VER, numV, allocator);
	numV.SetInt(pMaster->enc_savevsion);
	doc.AddMember(KEY_SAVE_VER, numV, allocator);
	numV.SetInt(pMaster->enc_curvsion);
	doc.AddMember(KEY_CURVER, numV, allocator);

	numV.SetInt(pMaster->enc_ethdevnum);
	doc.AddMember(KEY_ETH_NUM, numV, allocator);
	rapidjson::Value eth(rapidjson::kArrayType);
	for (uint i = 0; i < pMaster->enc_ethdevnum; i++)
	{
		rapidjson::Value val(rapidjson::kObjectType);
		strV.SetString((char*)pMaster->enc_ethdevname[i], allocator);
		val.AddMember(KEY_ETH_NAME, strV, allocator);
		numV.SetInt((pMaster->enc_ethdevipaddr[i][0]));
		val.AddMember(KEY_ETH_IPADDR, numV, allocator);
		eth.PushBack(val, allocator);
	}
	doc.AddMember(KEY_ETH_DEV, eth, allocator);

	// channel cfg
	for (uint i = 0; i < ENC_TOTAL_CHLMAX; i++)
	{
		shrmem_encchl_save(&pMaster->enc_chls[i], i);
	}

	// ip input
	rapidjson::Value total_ipinputs(rapidjson::kArrayType);
	for (int i = 0; i < ENC_MAX_IPINPUT_NUM; i++)
	{
		rapidjson::Value ipinput(rapidjson::kObjectType);
		ipinput.AddMember(KEY_IPIN_ENABLE, pMaster->enc_ipin[i].inp_enable, allocator);
		ipinput.AddMember(KEY_IPIN_IGMP, pMaster->enc_ipin[i].inp_igmp, allocator);
		ipinput.AddMember(KEY_IPIN_PROTO, pMaster->enc_ipin[i].inp_proto, allocator);
		{
			rapidjson::Value ethio(rapidjson::kObjectType);
			stENC_ETHIOSET& ethioset = pMaster->enc_ipin[i].inp_ethio;
			JSON_ETHIO(ethio, ethioset);
			ipinput.AddMember(KEY_ETHIO, ethio, allocator);
		}
		total_ipinputs.PushBack(ipinput, allocator);
	}


	doc.AddMember(KEY_IP_INPUT, total_ipinputs, allocator);

	// output for enc channel
	rapidjson::Value encOutputs(rapidjson::kArrayType);
	for (uint i = 0; i < ENC_TOTAL_CHLMAX; i++)
	{
		rapidjson::Value out(rapidjson::kObjectType);
		stENC_OUTSET& outset = pMaster->enc_output[i];
		out.AddMember(KEY_OUT_PROTO, outset.out_proto, allocator);
		out.AddMember(KEY_OUT_FILTER_NULL_PKT, outset.out_filte_nullpkt, allocator);
		out.AddMember(KEY_OUT_ENABLE_IP, outset.out_enable_ip, allocator);
		out.AddMember(KEY_OUT_ENABLE_ASI, outset.out_enable_asi, allocator);

		stENC_ETHIOSET& ethioset = outset.out_ethio;
		rapidjson::Value ethio(rapidjson::kObjectType);
		JSON_ETHIO(ethio, ethioset);
		out.AddMember(KEY_ETHIO, ethio, allocator);

		encOutputs.PushBack(out, allocator);
	}
	doc.AddMember(KEY_ENC_OUTPUT, encOutputs, allocator);

	// mux set
	rapidjson::Value mux(rapidjson::kObjectType);
	stENC_MUXSET& muxset = pMaster->enc_mptsmux;
	mux.AddMember(KEY_MUX_RATE, muxset.mux_maxrate_kb, allocator);
	mux.AddMember(KEY_MUX_ORG_NETID, muxset.mux_origin_nid, allocator);
	mux.AddMember(KEY_MUX_NETID, muxset.mux_netid, allocator);
	mux.AddMember(KEY_MUX_TRANSID, muxset.mux_transid, allocator);
	mux.AddMember(KEY_MUX_PCR_CORRECT, muxset.mux_pcr_correct, allocator);
	doc.AddMember(KEY_MUX_SET, mux, allocator);

	// mux output
	{
		rapidjson::Value out(rapidjson::kObjectType);
		stENC_OUTSET& outset = pMaster->enc_mptsout;
		out.AddMember(KEY_OUT_PROTO, outset.out_proto, allocator);
		out.AddMember(KEY_OUT_FILTER_NULL_PKT, outset.out_filte_nullpkt, allocator);
		out.AddMember(KEY_OUT_ENABLE_IP, outset.out_enable_ip, allocator);
		out.AddMember(KEY_OUT_ENABLE_ASI, outset.out_enable_asi, allocator);
		stENC_ETHIOSET& ethioset = outset.out_ethio;
		rapidjson::Value ethio(rapidjson::kObjectType);
		JSON_ETHIO(ethio, ethioset);
		out.AddMember(KEY_ETHIO, ethio, allocator);
		doc.AddMember(KEY_MUX_OUTPUT, out, allocator);
	}

	rapidjson::StringBuffer sb;
	rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
	doc.Accept(writer);

	u::io::File::write(cfgfile, sb.GetString(), sb.GetSize());
//	BW_INFO("%s\n", sb.GetString());
}

/*
{"inited":1,"appver":32,"setver":1,"savever":1,"curver":0,"ethnum":1,"ethdev":[{"name":"eth0","ipaddr":0}]}
 */
void shrmem_enc_load_slv(pENC_DEVSET_SLAVE pSlave)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/%s", g_cfgpath, ENC_SLV_CFG);
	std::string str;

	if (NULL == pSlave)
	{
		return;
	}
	if (!u::io::File::exists(cfgfile))
	{
		return;
	}
	u::AutoHeap content;
	u::io::File::read(content, cfgfile);

	rapidjson::Document	doc;
	doc.Parse(content.head());
	if (doc.HasParseError())
	{
		return;
	}

	GET_INT_VALUE(pSlave->enc_appvsion, KEY_APPVER, doc, END_APP_SLV_VER);
	GET_INT_VALUE(pSlave->enc_setvsion, KEY_SET_VER, doc, 1);
	GET_INT_VALUE(pSlave->enc_savevsion, KEY_SAVE_VER, doc, 1);
	GET_INT_VALUE(pSlave->enc_curvsion, KEY_CURVER, doc, 0);

	GET_INT_VALUE(pSlave->enc_ethdevnum, KEY_ETH_NUM, doc, ENC_ETHIFMAX_SLAVE);

	if (doc.HasMember(KEY_ETH_DEV) && doc[KEY_ETH_DEV].IsArray())
	{
		rapidjson::Value& ethdev = doc[KEY_ETH_DEV];
		for (uint i = 0; i < ethdev.Size() && i < ENC_ETHIFMAX_SLAVE; i++)
		{
			GET_STR_VALUE(str, KEY_ETH_NAME, ethdev[i], "");
			if (str.empty())
			{
				memset(pSlave->enc_ethdevname[i], 0, sizeof(pSlave->enc_ethdevname[i]));
			}
			else
			{
				snprintf((char*)pSlave->enc_ethdevname[i], sizeof(pSlave->enc_ethdevname[i]), "%s", str.c_str());
			}
			GET_INT_VALUE(pSlave->enc_ethdevipaddr[i][0], KEY_ETH_IPADDR, ethdev[i], 0);
		}
	}

	for (uint i = 0; i < ENC_MAX_CHL; i++)
	{
		shrmem_encchl_load(&pSlave->enc_chls[i], i);
	}
}

void shrmem_enc_save_slv(pENC_DEVSET_SLAVE pSlave)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/%s", g_cfgpath, ENC_SLV_CFG);

	if (NULL == pSlave)
	{
		return;
	}

	rapidjson::Document	doc;
	doc.SetObject();
	rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();

	rapidjson::Value strV(rapidjson::kStringType);
	rapidjson::Value numV(rapidjson::kNumberType);

	numV.SetInt(pSlave->enc_inited);
	doc.AddMember(KEY_INITED, numV, allocator);
	numV.SetInt(pSlave->enc_appvsion);
	doc.AddMember(KEY_APPVER, numV, allocator);
	numV.SetInt(pSlave->enc_setvsion);
	doc.AddMember(KEY_SET_VER, numV, allocator);
	numV.SetInt(pSlave->enc_savevsion);
	doc.AddMember(KEY_SAVE_VER, numV, allocator);
	numV.SetInt(pSlave->enc_curvsion);
	doc.AddMember(KEY_CURVER, numV, allocator);

	numV.SetInt(pSlave->enc_ethdevnum);
	doc.AddMember(KEY_ETH_NUM, numV, allocator);
	rapidjson::Value eth(rapidjson::kArrayType);
	for (uint i = 0; i < pSlave->enc_ethdevnum; i++)
	{
		rapidjson::Value val(rapidjson::kObjectType);
		strV.SetString((char*)pSlave->enc_ethdevname[i], allocator);
		val.AddMember(KEY_ETH_NAME, strV, allocator);
		numV.SetInt(pSlave->enc_ethdevipaddr[i][0]);
		val.AddMember(KEY_ETH_IPADDR, numV, allocator);
		eth.PushBack(val, allocator);
	}
	doc.AddMember(KEY_ETH_DEV, eth, allocator);

	rapidjson::StringBuffer sb;
	rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
	doc.Accept(writer);

	u::io::File::write(cfgfile, sb.GetString(), sb.GetSize());
//	BW_INFO("save to cfg[%s], %s\n", cfgfile, sb.GetString());

	for (uint i = 0; i < ENC_MAX_CHL; i++)
	{
		shrmem_encchl_save(&pSlave->enc_chls[i], i);
	}
}

void shrmem_encchl_save(pENC_CHLSET pchlset, int idx)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/chn_%02d.cfg", g_cfgpath, idx);

	if (NULL == pchlset || idx < 0)
	{
		return;
	}

	rapidjson::Document	doc;
	doc.SetObject();
	rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();

	rapidjson::Value strV(rapidjson::kStringType);

	doc.AddMember(KEY_CHL_ISRUN, pchlset->encchl_isrun, allocator);
	doc.AddMember(KEY_CHL_ISIN_MPTS, pchlset->encchl_ismptssel, allocator);

	// video set
	rapidjson::Value vid(rapidjson::kObjectType);
	stENC_VIDSET& vidset = pchlset->encchl_vid;
	vid.AddMember(KEY_V_CODEC, vidset.vid_codec, allocator);
	vid.AddMember(KEY_V_PROFILE, vidset.vid_profile, allocator);
	vid.AddMember(KEY_V_LEVEL, vidset.vid_level, allocator);
	vid.AddMember(KEY_V_RCTYPE, vidset.vid_rctype, allocator);
	vid.AddMember(KEY_V_WIDTH, vidset.vid_width, allocator);
	vid.AddMember(KEY_V_HEIGHT, vidset.vid_height, allocator);
	vid.AddMember(KEY_V_BITRATE, vidset.vid_bitrate_kb, allocator);

	vid.AddMember(KEY_V_BIT_FLU, vidset.vid_fluctuate, allocator);
	vid.AddMember(KEY_V_BIT_MIN, vidset.vid_bitrate_min, allocator);
	vid.AddMember(KEY_V_BIT_MAX, vidset.vid_bitrate_max, allocator);
	vid.AddMember(KEY_V_GOPSIZE, vidset.vid_gopsize, allocator);
	vid.AddMember(KEY_V_FPSNUM, vidset.vid_fpsnum, allocator);
	vid.AddMember(KEY_V_FPSDEN, vidset.vid_fpsden, allocator);
	vid.AddMember(KEY_V_DAR, vidset.vid_dar, allocator);
	doc.AddMember(KEY_VID_SET, vid, allocator);

	// osd set
	rapidjson::Value osd(rapidjson::kArrayType);
	for (int i = 0; i < ENC_OSD_MAX_OVERLAY; i++)
	{
		stENC_OSDSET& osdset = pchlset->encchl_osd[i];
		rapidjson::Value v(rapidjson::kObjectType);
		v.AddMember(KEY_OSD_ENABLE, osdset.osd_enable, allocator);
		v.AddMember(KEY_OSD_TYPE, osdset.osd_type, allocator);
		if (osdset.osd_type == BWENC_OSD_TYPE_TEXT)
		{
			rapidjson::Value sub(rapidjson::kObjectType);
			stENC_SUBSET& subset = osdset.osd_cfg.osd_sub;
			strV.SetString((char*)subset.sub_content, allocator);
			sub.AddMember(KEY_SUB_CONTENET, strV, allocator);
			strV.SetString((char*)subset.sub_font, allocator);
			sub.AddMember(KEY_SUB_FONT, strV, allocator);
			sub.AddMember(KEY_SUB_FONTSIZE, subset.sub_fontsize, allocator);
			sub.AddMember(KEY_SUB_FONTSTYLE, subset.sub_fontstyle, allocator);
			sub.AddMember(KEY_SUB_X, subset.sub_x, allocator);
			sub.AddMember(KEY_SUB_Y, subset.sub_y, allocator);
			sub.AddMember(KEY_SUB_FONTCOLOR, subset.sub_fontcolor, allocator);
			sub.AddMember(KEY_SUB_BACKCOLOR, subset.sub_backcolor, allocator);
			sub.AddMember(KEY_SUB_MOVDIR, subset.sub_movdir, allocator);
			sub.AddMember(KEY_SUB_MOVSPEED, subset.sub_movspeed, allocator);

			v.AddMember(KEY_SUB_SET, sub, allocator);
		}
		else if (osdset.osd_type == BWENC_OSD_TYPE_LOGO)
		{
			rapidjson::Value logo(rapidjson::kObjectType);
			stENC_LOGOSET& logoset = osdset.osd_cfg.osd_logo;
			logo.AddMember(KEY_LOGO_NUM, logoset.logo_num, allocator);
			rapidjson::Value url(rapidjson::kArrayType);
			for (int i = 0; i < logoset.logo_num && i < ENC_OSD_MAX_SLIDE_NUM; i++)
			{
				strV.SetString((char*)logoset.logo_url[i], allocator);
				url.PushBack(strV, allocator);
			}
			logo.AddMember(KEY_LOGO_URL, url, allocator);
			logo.AddMember(KEY_LOGO_OPACITY, logoset.logo_opacity, allocator);
			logo.AddMember(KEY_LOGO_WIDTH, logoset.logo_width, allocator);
			logo.AddMember(KEY_LOGO_HEIGHT, logoset.logo_height, allocator);
			logo.AddMember(KEY_LOGO_X, logoset.logo_x, allocator);
			logo.AddMember(KEY_LOGO_Y, logoset.logo_y, allocator);
			logo.AddMember(KEY_LOGO_MOVDIR, logoset.logo_movdir, allocator);
			logo.AddMember(KEY_LOGO_MOVSPEED, logoset.logo_movspeed, allocator);

			v.AddMember(KEY_LOGO_SET, logo, allocator);
		}
		else if (osdset.osd_type == BWENC_OSD_TYPE_QRCODE)
		{
			rapidjson::Value qr(rapidjson::kObjectType);
			stENC_QRCODE& qrset = osdset.osd_cfg.osd_qr;
			strV.SetString((char*)qrset.qr_url, allocator);
			qr.AddMember(KEY_QR_URL, strV, allocator);
			qr.AddMember(KEY_QR_OPACITY, qrset.qr_opacity, allocator);
			qr.AddMember(KEY_QR_WIDTH, qrset.qr_width, allocator);
			qr.AddMember(KEY_QR_HEIGHT, qrset.qr_height, allocator);
			qr.AddMember(KEY_QR_X, qrset.qr_x, allocator);
			qr.AddMember(KEY_QR_Y, qrset.qr_y, allocator);

			v.AddMember(KEY_QR_SET, qr, allocator);
		}

		// time set
		rapidjson::Value tmset(rapidjson::kArrayType);
		for (int i = 0; i < ENC_WEEK_DAYS; i++)
		{
			rapidjson::Value day(rapidjson::kObjectType);
			day.AddMember(KEY_OSD_TM_WEEKDAY, i, allocator);
			rapidjson::Value tms_array(rapidjson::kArrayType);
			for (int k = 0; k < ENC_OSD_MAX_TM_NUM; k++)
			{
				stENC_OSD_TMSET& tset = osdset.osd_effect_tm[i][k];
				rapidjson::Value t(rapidjson::kObjectType);
				t.AddMember(KEY_OSD_START_TM, tset.tm_start_sec, allocator);
				t.AddMember(KEY_OSD_END_TM, tset.tm_end_sec, allocator);
				tms_array.PushBack(t, allocator);
			}
			day.AddMember(KEY_OSD_TMSET, tms_array, allocator);
			tmset.PushBack(day, allocator);
		}
		v.AddMember(KEY_OSD_TMSET, tmset, allocator);

		osd.PushBack(v, allocator);
	}
	doc.AddMember(KEY_OSD_SET, osd, allocator);

	// aud set
	rapidjson::Value aud(rapidjson::kObjectType);
	stENC_AUDSET& audset = pchlset->encchl_aud;
	aud.AddMember(KEY_A_CODEC, audset.aud_codec, allocator);
	aud.AddMember(KEY_A_VOL, audset.aud_vol, allocator);
	aud.AddMember(KEY_A_BITRATE, audset.aud_bitrate_kb, allocator);
	aud.AddMember(KEY_A_SMP_RATE, audset.aud_smp_rate, allocator);
	aud.AddMember(KEY_A_SMP_FMT, audset.aud_smp_fmt, allocator);
	aud.AddMember(KEY_A_CHN, audset.aud_channle, allocator);
	doc.AddMember(KEY_AUD_SET, aud, allocator);

	// ts set
	rapidjson::Value ts(rapidjson::kObjectType);
	stENC_TSSET& tsset = pchlset->encchl_ts;
	strV.SetString((char*)tsset.ts_service_name, allocator);
	ts.AddMember(KEY_SERVICE_NAME, strV, allocator);
	strV.SetString((char*)tsset.ts_provider_name, allocator);
	ts.AddMember(KEY_PROVIDER_NAME, strV, allocator);
	ts.AddMember(KEY_PMT_PID, tsset.ts_pmt_pid, allocator);
	ts.AddMember(KEY_SERVICE_ID, tsset.ts_service_id, allocator);
	ts.AddMember(KEY_PCR_PID, tsset.ts_pcr_pid, allocator);
	ts.AddMember(KEY_VID_PID, tsset.ts_vid_pid, allocator);
	ts.AddMember(KEY_AUD_PID, tsset.ts_aud_pid, allocator);
	ts.AddMember(KEY_PCR_INTERVAL_MS, tsset.ts_pcr_interval_ms, allocator);
	ts.AddMember(KEY_MUXRATE, tsset.ts_muxrate_kb, allocator);
	doc.AddMember(KEY_TS_SET, ts, allocator);

	// ETHIO
	rapidjson::Value ethio(rapidjson::kObjectType);
	stENC_ETHIOSET& ethioset = pchlset->encchl_output;
	JSON_ETHIO(ethio, ethioset)
	doc.AddMember(KEY_ETHIO, ethio, allocator);

	rapidjson::StringBuffer sb;
	rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
	doc.Accept(writer);

	u::io::File::write(cfgfile, sb.GetString(), sb.GetSize());
//	BW_INFO("save to cfg[%s], %s\n", cfgfile, sb.GetString());
}

void shrmem_encchl_load(pENC_CHLSET pchlset, int idx)
{
	char cfgfile[MAX_PATH];
	snprintf(cfgfile, sizeof(cfgfile), "%s/chn_%02d.cfg", g_cfgpath, idx);
	std::string str;

	if (NULL == pchlset || idx < 0)
	{
		return;
	}

	if (!u::io::File::exists(cfgfile))
	{
		return;
	}

	u::AutoHeap content;
	u::io::File::read(content, cfgfile);

	rapidjson::Document	doc;
	doc.Parse(content.head());
	if (doc.HasParseError())
	{
		return;
	}

	GET_INT_VALUE(pchlset->encchl_isrun, KEY_CHL_ISRUN, doc, 0);
	GET_INT_VALUE(pchlset->encchl_ismptssel, KEY_CHL_ISIN_MPTS, doc, 0);

	// video set
	stENC_VIDSET& vidset = pchlset->encchl_vid;
	if (doc.HasMember(KEY_VID_SET) && doc[KEY_VID_SET].IsObject())
	{
		rapidjson::Value& vid = doc[KEY_VID_SET];
		GET_INT_VALUE(vidset.vid_codec, KEY_V_CODEC, vid, BWENC_VID_CODEC_H264);
		GET_INT_VALUE(vidset.vid_profile, KEY_V_PROFILE, vid, BWENC_VID_PROFILE_BASELINE);
		GET_INT_VALUE(vidset.vid_level, KEY_V_LEVEL, vid, 0);
		GET_INT_VALUE(vidset.vid_rctype, KEY_V_RCTYPE, vid, BWENC_VID_RC_CBR);
		GET_INT_VALUE(vidset.vid_width, KEY_V_WIDTH, vid, 1920);
		GET_INT_VALUE(vidset.vid_height, KEY_V_HEIGHT, vid, 1080);
		GET_INT_VALUE(vidset.vid_bitrate_kb, KEY_V_BITRATE, vid, 4096);

		GET_INT_VALUE(vidset.vid_fluctuate, KEY_V_BIT_FLU, vid, 0);
		GET_INT_VALUE(vidset.vid_bitrate_min, KEY_V_BIT_MIN, vid, vidset.vid_bitrate_kb);
		GET_INT_VALUE(vidset.vid_bitrate_max, KEY_V_BIT_MAX, vid, vidset.vid_bitrate_kb);
		GET_INT_VALUE(vidset.vid_gopsize, KEY_V_GOPSIZE, vid, 25);
		GET_INT_VALUE(vidset.vid_fpsnum, KEY_V_FPSNUM, vid, 25);
		GET_INT_VALUE(vidset.vid_fpsden, KEY_V_FPSDEN, vid, 1);
		GET_INT_VALUE(vidset.vid_dar, KEY_V_DAR, vid, BWENC_VID_DAR_16_9);
	}

	// osd set
	if (doc.HasMember(KEY_OSD_SET) && doc[KEY_OSD_SET].IsArray())
	{
		rapidjson::Value& osds = doc[KEY_OSD_SET];
		for (uint i = 0; i < ENC_OSD_MAX_OVERLAY && i < osds.Size(); i++)
		{
			stENC_OSDSET& osdset = pchlset->encchl_osd[i];
			rapidjson::Value& osd = osds[i];
			GET_INT_VALUE(osdset.osd_enable, KEY_OSD_ENABLE, osd, 0);
			GET_INT_VALUE(osdset.osd_type, KEY_OSD_TYPE, osd, BWENC_OSD_TYPE_INVALID);

			if (osdset.osd_type == BWENC_OSD_TYPE_TEXT)
			{
				if (osd.HasMember(KEY_SUB_SET) && osd[KEY_SUB_SET].IsObject())
				{
					rapidjson::Value& sub = osd[KEY_SUB_SET];
					stENC_SUBSET& subset = osdset.osd_cfg.osd_sub;
					GET_STR_VALUE(str, KEY_SUB_CONTENET, sub, "");
					snprintf((char*)subset.sub_content, sizeof(subset.sub_content), "%s", str.c_str());
					GET_STR_VALUE(str, KEY_SUB_FONT, sub, "");
					snprintf((char*)subset.sub_font, sizeof(subset.sub_font), "%s", str.c_str());
					
					GET_INT_VALUE(subset.sub_fontsize, KEY_SUB_FONTSIZE, sub, 0);
					GET_INT_VALUE(subset.sub_fontstyle, KEY_SUB_FONTSTYLE, sub, 0);
					
					GET_INT_VALUE(subset.sub_fontcolor, KEY_SUB_FONTCOLOR, sub, 0);
					GET_INT_VALUE(subset.sub_backcolor, KEY_SUB_BACKCOLOR, sub, 0);
					GET_INT_VALUE(subset.sub_x, KEY_SUB_X, sub, 0);
					GET_INT_VALUE(subset.sub_y, KEY_SUB_Y, sub, 0);
					GET_INT_VALUE(subset.sub_movdir, KEY_SUB_MOVDIR, sub, 0);
					GET_INT_VALUE(subset.sub_movspeed, KEY_SUB_MOVSPEED, sub, 0);
				}
			}
			else if (osdset.osd_type == BWENC_OSD_TYPE_LOGO)
			{
				stENC_LOGOSET& logoset = osdset.osd_cfg.osd_logo;
				if (osd.HasMember(KEY_LOGO_SET) && osd[KEY_LOGO_SET].IsObject())
				{
					rapidjson::Value& logo = osd[KEY_LOGO_SET];
					if (logo.HasMember(KEY_LOGO_URL) && logo[KEY_LOGO_URL].IsArray())
					{
						rapidjson::Value& v = logo[KEY_LOGO_URL];
						GET_INT_VALUE(logoset.logo_num, KEY_LOGO_NUM, logo, 0);
						for (uint i = 0; i < v.Size() && i < logoset.logo_num && i < ENC_OSD_MAX_SLIDE_NUM; i++)
						{
							snprintf((char*)logoset.logo_url[i], sizeof(logoset.logo_url[i]), "%s", v[i].GetString());
						}
					}
					GET_INT_VALUE(logoset.logo_opacity, KEY_LOGO_OPACITY, logo, 0);
					GET_INT_VALUE(logoset.logo_width, KEY_LOGO_WIDTH, logo, 0);
					GET_INT_VALUE(logoset.logo_height, KEY_LOGO_HEIGHT, logo, 0);
					GET_INT_VALUE(logoset.logo_x, KEY_LOGO_X, logo, 0);
					GET_INT_VALUE(logoset.logo_y, KEY_LOGO_Y, logo, 0);
					GET_INT_VALUE(logoset.logo_movdir, KEY_LOGO_MOVDIR, logo, 0);
					GET_INT_VALUE(logoset.logo_movspeed, KEY_LOGO_MOVSPEED, logo, 0);
				}
			}
			else if (osdset.osd_type == BWENC_OSD_TYPE_QRCODE)
			{
				stENC_QRCODE& qrset = osdset.osd_cfg.osd_qr;
				if (osd.HasMember(KEY_QR_SET) && osd[KEY_QR_SET].IsObject())
				{
					rapidjson::Value& qr = osd[KEY_QR_SET];
					GET_STR_VALUE(str, KEY_QR_URL, qr, "");
					snprintf((char*)qrset.qr_url, sizeof(qrset.qr_url), "%s", str.c_str());
					GET_INT_VALUE(qrset.qr_opacity, KEY_QR_OPACITY, qr, 0);
					GET_INT_VALUE(qrset.qr_width, KEY_QR_WIDTH, qr, 0);
					GET_INT_VALUE(qrset.qr_height, KEY_QR_HEIGHT, qr, 0);
					GET_INT_VALUE(qrset.qr_x, KEY_QR_X, qr, 0);
					GET_INT_VALUE(qrset.qr_y, KEY_QR_Y, qr, 0);
				}
			}

			// tm set
			// FIXME maybe struct should be modified
			if (osd.HasMember(KEY_OSD_TMSET) && osd[KEY_OSD_TMSET].IsArray())
			{
				rapidjson::Value& t_m = osd[KEY_OSD_TMSET];
				for (uint m = 0; m < ENC_WEEK_DAYS && m < t_m.Size(); m++)
				{
					rapidjson::Value& day = t_m[m];
					
					int weekday=0;
					GET_INT_VALUE(weekday, "weekday", day, 0);
					if(weekday < 0 && weekday > 6)
					{
						continue;
					}

					if (day.HasMember(KEY_OSD_TMSET) && day[KEY_OSD_TMSET].IsArray())
					{
						rapidjson::Value& times = day[KEY_OSD_TMSET];
						
						for(uint n = 0; n < ENC_OSD_MAX_TM_NUM && n < t_m.Size(); n++)
						{
							rapidjson::Value& time = times[n];
					
							stENC_OSD_TMSET &timeset = osdset.osd_effect_tm[weekday][n];
						
							GET_INT_VALUE(timeset.tm_start_sec, KEY_OSD_START_TM, time, 0);
							GET_INT_VALUE(timeset.tm_end_sec, KEY_OSD_END_TM, time, 0);
							
						}
					}
				}
			}
			
		}
	}

	// audio set
	if (doc.HasMember(KEY_AUD_SET) && doc[KEY_AUD_SET].IsObject())
	{
		rapidjson::Value& aud = doc[KEY_AUD_SET];
		stENC_AUDSET& audset = pchlset->encchl_aud;
		GET_INT_VALUE(audset.aud_codec, KEY_A_CODEC, aud, BWENC_AUD_CODEC_AAC_LC);
		GET_INT_VALUE(audset.aud_vol, KEY_A_VOL, aud, 100);
		GET_INT_VALUE(audset.aud_bitrate_kb, KEY_A_BITRATE, aud, 128);
		GET_INT_VALUE(audset.aud_smp_rate, KEY_A_SMP_RATE, aud, 48000);
		GET_INT_VALUE(audset.aud_smp_fmt, KEY_A_SMP_FMT, aud, BWENC_AUD_SMPFMT_S16);
		GET_INT_VALUE(audset.aud_channle, KEY_A_CHN, aud, 2);
	}

	// ts set
	if (doc.HasMember(KEY_TS_SET) && doc[KEY_TS_SET].IsObject())
	{
		rapidjson::Value& ts = doc[KEY_TS_SET];
		stENC_TSSET& tsset = pchlset->encchl_ts;
		GET_STR_VALUE(str, KEY_SERVICE_NAME, ts, "bwsctv")
		snprintf((char*)tsset.ts_service_name, sizeof(tsset.ts_service_name), "%s", str.c_str());
		GET_STR_VALUE(str, KEY_PROVIDER_NAME, ts, "WWW.BWSCTV.COM");
		snprintf((char*)tsset.ts_provider_name, sizeof(tsset.ts_provider_name), "%s", str.c_str());
		GET_INT_VALUE(tsset.ts_pmt_pid, KEY_PMT_PID, ts, 0);
		GET_INT_VALUE(tsset.ts_service_id, KEY_SERVICE_ID, ts, 0);
		GET_INT_VALUE(tsset.ts_pcr_pid, KEY_PCR_PID, ts, 0);
		GET_INT_VALUE(tsset.ts_vid_pid, KEY_VID_PID, ts, 0);
		GET_INT_VALUE(tsset.ts_aud_pid, KEY_AUD_PID, ts, 0);
		GET_INT_VALUE(tsset.ts_pcr_interval_ms, KEY_PCR_INTERVAL_MS, ts, 0);
		GET_INT_VALUE(tsset.ts_muxrate_kb, KEY_MUXRATE, ts, 0);
	}

	// output
	if (doc.HasMember(KEY_ETHIO) && doc[KEY_ETHIO].IsObject())
	{
		stENC_ETHIOSET& ethioset = pchlset->encchl_output;
		rapidjson::Value& ethio = doc[KEY_ETHIO];
		UNJSON_ETHIO(ethioset, ethio)
	}
}


void shrmem_enc_load_slv_v2(pENC_DEVSET_SLAVE pSlave)
{

}
